package org.campuscontent.ui;

import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.io.Serializable;
import java.util.EventObject;

import javax.swing.DefaultCellEditor;
import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JTree;

import org.campuscontent.model.AutomataCellViewFactory;
import org.campuscontent.model.AutomataConstants;
import org.jgraph.JGraph;
import org.jgraph.graph.CellViewRenderer;
import org.jgraph.graph.DefaultGraphCell;
import org.jgraph.graph.EdgeView;
import org.jgraph.graph.GraphCellEditor;
import org.jgraph.graph.VertexRenderer;
import org.jgraph.graph.VertexView;

public class AutomataChameleonView extends VertexView implements AutomataConstants
{
    public AutomataChameleonView( Object cell )
    {
        super( cell );

        setCell( cell );
    }

    public Point2D getPerimeterPoint( EdgeView edge, Point2D source, Point2D p )
    {
        if ( getRenderer() instanceof VertexRenderer )
        {
            Point2D perimeterPoint = ((VertexRenderer) getRenderer()).getPerimeterPoint( this, source, p );
            
            // System.out.println( p + "  --.-- " + perimeterPoint );
            
            return perimeterPoint;
        }
        
        return super.getPerimeterPoint( edge, source, p );
    }

    public CellViewRenderer getRenderer()
    {
        DefaultGraphCell cell = (DefaultGraphCell) getCell();
        NodeType type = AutomataCellViewFactory.getNodeType( cell );

        if ( type == null ) type = NodeType.START;
        
        if ( type.equals( NodeType.STARTEND ) )
        {
            return se.getRenderer();
        }
        else if ( type.equals( NodeType.START ) )
        {
            return start.getRenderer();
        }
        else if ( type.equals( NodeType.END ) )
        {
            return end.getRenderer();
        }
        
        return normal.getRenderer();
    }

    public static CellViewRenderer getRenderer( DefaultGraphCell cell )
    {
        NodeType type = AutomataCellViewFactory.getNodeType( cell );
        
        if ( type == null ) type = NodeType.START;
        
        if ( type.equals( NodeType.STARTEND ) )
        {
            return se.getRenderer();
        }
        else if ( type.equals( NodeType.START ) )
        {
            return start.getRenderer();
        }
        else if ( type.equals( NodeType.END ) )
        {
            return end.getRenderer();
        }
        
        return normal.getRenderer();
    }
    
    public GraphCellEditor getEditor()
    {
        ((CamaleonCellEditor)camaleonEditor).setCell( (DefaultGraphCell)getCell() );
        return camaleonEditor;
    }
    
    protected static transient GraphCellEditor camaleonEditor = new CamaleonCellEditor( new CamaleonMaskEditor() );

    protected static transient StartEndNodeView  se  = new StartEndNodeView();
    protected static transient StartNodeView  start  = new StartNodeView   ();
    protected static transient NormalNodeView normal = new NormalNodeView  ();
    protected static transient EndNodeView    end    = new EndNodeView     ();
    
    public static class CamaleonVerifier extends InputVerifier
    {
        public boolean verify( JComponent input )
        {
//            JTextField tf = (JTextField) input;
//            String str = tf.getText();
            
            return true;
        }
    }

    public static class CamaleonMaskEditor extends JTextField
    {
        public CamaleonMaskEditor()
        {
            super( 10 );

            setInputVerifier( new CamaleonVerifier() );
        }
    }

    public static class CamaleonCellEditor extends DefaultCellEditor implements GraphCellEditor
    {
        protected transient EditorDelegate delegator;
        protected transient DefaultGraphCell cell;
        protected transient JGraph graph;

        public CamaleonCellEditor( final JTextField field )
        {
            super( field ); // dummy
            
            this.clickCountToStart = 2;

            delegator = new EditorDelegate()
            {
                public void setValue( Object value )
                {
                    this.oldvalue = value;
                    if ( value != null )
                    {
                        ((JTextField)editorComponent).setText( (String)value );
                    }
                }

                public Object getCellEditorValue()
                {
                    String newvalue = ((JTextField)editorComponent).getText();

                    boolean exist = ((AutomataGraph)graph).existNodeNameAlready( newvalue );
                    
                    if ( !exist )
                    {
                        AutomataCellViewFactory.setNodeName( cell, newvalue );
                        return newvalue;
                    }
                    else
                    {
                        Toolkit.getDefaultToolkit().beep();
                        return oldvalue;
                    }
                }
            };

            ((JTextField)editorComponent).addActionListener( delegator );
        }
        
        public void setCell( DefaultGraphCell cell )
        {
            this.cell = cell;
        }
        
        //
        // GraphCellEditor Interface
        //
        public Component getGraphCellEditorComponent( JGraph graph, Object value, boolean isSelected )
        {
            this.graph = graph;

            String stringValue = graph.convertValueToString( value );

            delegator.setValue( stringValue );

            return editorComponent;
        }

        public Component getComponent()
        {
            return editorComponent;
        }

        public void setClickCountToStart( int count )
        {
            clickCountToStart = count;
        }

        public int getClickCountToStart()
        {
            return clickCountToStart;
        }

        public Object getCellEditorValue()
        {
            return delegator.getCellEditorValue();
        }

        public boolean isCellEditable( EventObject anEvent )
        {
            return delegator.isCellEditable( anEvent );
        }

        public boolean shouldSelectCell( EventObject anEvent )
        {
            return delegator.shouldSelectCell( anEvent );
        }

        public boolean stopCellEditing()
        {
            return delegator.stopCellEditing();
        }

        public void cancelCellEditing()
        {
            delegator.cancelCellEditing();
        }

        public Component getTreeCellEditorComponent( JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row )
        {
            String stringValue = tree.convertValueToText( value, isSelected, expanded, leaf, row, false );

            delegator.setValue( stringValue );

            return editorComponent;
        }

        public Component getTableCellEditorComponent( JTable table, Object value, boolean isSelected, int row, int column )
        {
            delegator.setValue( value );

            return editorComponent;
        }

        protected class EditorDelegate implements ActionListener, ItemListener, Serializable
        {
            protected Object oldvalue;

            public Object getCellEditorValue()
            {
                return oldvalue;
            }

            public void setValue( Object value )
            {
                this.oldvalue = value;
            }

            public boolean isCellEditable( EventObject anEvent )
            {
                if ( anEvent instanceof MouseEvent )
                {
                    return ((MouseEvent) anEvent).getClickCount() >= clickCountToStart;
                }
                return true;
            }

            public boolean shouldSelectCell( EventObject anEvent )
            {
                return true;
            }

            public boolean startCellEditing( EventObject anEvent )
            {
                return true;
            }

            public boolean stopCellEditing()
            {
                fireEditingStopped();
                return true;
            }

            public void cancelCellEditing()
            {
                JGraph graph = CamaleonCellEditor.this.graph;

                if ( graph != null )
                {
                    graph.invalidate();
                    graph.validate();
                    graph.repaint();
                }

                fireEditingCanceled();
            }

            public void actionPerformed( ActionEvent e )
            {
                CamaleonCellEditor.this.stopCellEditing();
            }

            public void itemStateChanged( ItemEvent e )
            {
                CamaleonCellEditor.this.stopCellEditing();
            }
        }

    }
}
